#include "ExampleSet.h"

#include "IntegralHist.h"

#include <stdlib.h>
#include <string>
#include <stdio.h>

#include <iostream>

using namespace std;

//////////////////////////////////////////////////////////////////
// ExampleSet Object											//
//////////////////////////////////////////////////////////////////

// Constructor for set of training example file names. This is 
// loaded before loading the training set data into memory so that
// the we can calculate the full size of the training data and 
// decide how to proceed with training. If the data fits into the 
// RAM, we proceed by loading all of it into memory.
ExampleSet::ExampleSet(char *directory, bool label)
{
	_n = 0;
	_head = NULL;
	_tail = NULL;
	AddToSet(directory,"*.png",label);
	AddToSet(directory,"*.jpg",label);
	AddToSet(directory,"*.jpeg",label);
	AddToSet(directory,"*.bmp",label);
}

// Copy constructor
ExampleSet::ExampleSet(const ExampleSet &init)
{
	// Copy number of examples across
	_n = init._n;

	// Check if we need to copy stuff across
	if(init._head)
	{
		// Initialise the beginning of the list with the correct image
		_head = new ExampleNode;
		if(init._head->name)
		{
			strcpy_s(_head->name,init._head->name);
			strcpy_s(_head->path,init._head->path);
			_head->_label = init._head->_label;
		}
		_head->next = NULL;
		_head->previous = NULL;
		_tail = _head;

		ExampleNode* temp = init._head;

		// Traverse the list and copy everything across
		while(temp->next)
		{
			_tail->next = new ExampleNode;
			strcpy_s(_tail->next->name,temp->next->name);
			strcpy_s(_tail->next->path,temp->next->path);
			_tail->next->_label = temp->next->_label;
			_tail->next->next = NULL;
			_tail->next->previous = _tail;
			_tail = _tail->next;
			temp = temp->next;
		}
	}
	else
	{
		_head = NULL;
		_tail = NULL;
	}
}

// Destructor
ExampleSet::~ExampleSet()
{
	// Loop while we are not at the head node
	if(_tail)
		while(_tail->previous)
		{
			// Jump back one
			_tail = _tail->previous;
			if(_tail->next)
				delete _tail->next;
		}

	// Delete the head node
	if(_head)
		delete _head;
}

// This function adds file names to a set from a directory.
void ExampleSet::AddToSet(char *directory, bool label)
{
	AddToSet(directory,"*.png",label);
	AddToSet(directory,"*.jpg",label);
	AddToSet(directory,"*.jpeg",label);
	AddToSet(directory,"*.bmp",label);
}

// This function adds file names to a set from a directory.
bool ExampleSet::AddToSet(char *directory, char *ext, bool label)
{
	// Create string for finding image files
	char file_find[100];
	strcpy_s(file_find,directory);
	strcat_s(file_find,ext);

	// Create string for file path name
	char current_file[100];

	// Get data for first file
	WIN32_FIND_DATA findFileData;
	HANDLE hFind = FindFirstFile(file_find, &findFileData);
	if(hFind == INVALID_HANDLE_VALUE)
		return false;
	strcpy_s(current_file,directory);
	strcat_s(current_file,findFileData.cFileName);

	// Check if any files have already been added
	if(_head)
	{
		// Add to the exisiting list
		_tail->next = new ExampleNode;

		strcpy_s(_tail->next->name,findFileData.cFileName);
		strcpy_s(_tail->next->path,directory);
		_tail->next->_label = label;

		_tail->next->next = NULL;
		_tail->next->previous = _tail;
		_tail = _tail->next;
		_n++;
	}
	else
	{
		// Create head of list
		_head = new ExampleNode;

		strcpy_s(_head->name,findFileData.cFileName);
		strcpy_s(_head->path,directory);
		_head->_label = label;

		_head->next = NULL;
		_head->previous = NULL;
		_tail = _head;
		_n = 1;
	}

	// Fill the rest of the list with the remaining files
	while(FindNextFile(hFind,&findFileData))
	{
		strcpy_s(current_file,directory);
		strcat_s(current_file,findFileData.cFileName);
		_tail->next = new ExampleNode;

		strcpy_s(_tail->next->name,findFileData.cFileName);
		strcpy_s(_tail->next->path,directory);
		_tail->next->_label = label;

		_tail->next->next = NULL;
		_tail->next->previous = _tail;
		_tail = _tail->next;
		_n++;
	}

	return true;
}

// This function tells us the size of data set 
float ExampleSet::GetSizeOfSet()
{
	return static_cast<float>((_n*130*66*ORIENTATION_BINS*4))/1000000000;
}

// This function prints out the information from a set of examples
void ExampleSet::PrintSet()
{
	ExampleNode* temp = _head;

	while(temp)
	{
		cout << temp->path << temp->name << endl;
		temp = temp->next;
	}
}